# -*- coding: utf-8 -*-

import requests
import random
import string
import binascii
import os
from qiniu import Auth, put_file, etag, put_data
from project.settings import (
    QINIU_accessKey,
    QINIU_secretKey,
    QINIU_videoBucketName,
    QINIU_imgBucketName,
    QINIU_imgBucketDomain,
    QINIU_textBucketName,
    QINIU_textBucketDomain,
    QINIU_videoBucketDomain,
    QINIU_docBucketName,
    QINIU_docBucketDomain)


class QiNiuService(object):
    """
    demo:
    qiniuObj = QiNiuService('img')
    fileKey, fileHash, fileUrl = qiniuObj.upload_file('F:/123.jpg') # 本地上传
    ---
    f = open('F:/123.jpg')
    fileKey, fileUrl = qiniuObj.upload_file_by_steam(f, '123.jpg') # 基于流上传
    ---
    status, content = qiniuObj.download_file('Dg4q8Jhu.jpg')
    if status == 200:
        path = content
    else:
        msg = content
    """
    bucketNameDict = {'img': QINIU_imgBucketName, 'video': QINIU_videoBucketName,
                      'text': QINIU_textBucketName, 'doc': QINIU_docBucketName}
    bucketDomainDict = {'img': QINIU_imgBucketDomain, 'video': QINIU_videoBucketDomain,
                        'text': QINIU_textBucketDomain, 'doc': QINIU_docBucketDomain}
    defaultPath = os.path.dirname(os.path.dirname(__file__))

    def __init__(self, bucketType):
        """
        :param bucketType: bucket类型
        """
        # self._filepath = filepath
        self.auth = Auth(QINIU_accessKey, QINIU_secretKey)
        self.bucketType = bucketType
        # self.targetName = targetName if targetName else QiNiuService.random_str()

    @property
    def _bucket_name(self):
        """
        依据类参数targetName获取bucketname
        """
        bucket_name = self.bucketNameDict.get(self.bucketType)
        if bucket_name:
            return bucket_name
        else:
            raise TypeError("Wrong type of bucketName")

    @property
    def _bucket_domain(self):
        """
        依据类参数targetName获取bucketDomain
        """
        bucketDomain = self.bucketDomainDict.get(self.bucketType)
        if not bucketDomain:
            raise TypeError("Wrong type of bucketName")
        return bucketDomain

    @property
    def filepath(self):
        return self._filepath

    @filepath.setter
    def filepath(self, value):
        """
        鉴别filepath的合法性，_fileExtensions文件后缀名
        """
        if not os.path.isfile(value):
            raise IOError("The path is not exists")
        else:
            self._filepath = value
            self._fileExtensions = os.path.splitext(os.path.split(self._filepath)[1])[1]

    @staticmethod
    def random_str(randomlength=8):
        """
        生成随机8位数的字符串
        """
        a = list(string.ascii_letters+string.digits)
        random.shuffle(a)
        return ''.join(a[:randomlength])

    def generate_private_url(self, key):
        """
        :param key: 文件名(key)
        :return: 私人空间地址
        """
        return '%s/%s' % (self._bucket_domain, key)

    def to_binfile(self, data):
        # fileNew = open(os.path.dirname(os.path.dirname(__file__))+'1.txt', 'wb')
        # lines = data.readlines()
        # for line in lines:
        #     curLine = line.split(' ')
        #     for i in range(len(curLine)):
        #         if len(curLine[i]):
        #             continue
        #         parsedata = struct.pack("f", float(curLine[i]))
        #         fileNew.write(parsedata)
        #     fileNew.write('\n')
        # data.close()
        # return fileNew
        return bin(int(binascii.hexlify(data.read()), 16))


    def upload_file(self, filepath, targetKey=None):
        """
        依据本地文件上传七牛云
        :param filepath: 本地文件路径
        :param targetKey: 上传成功后的文件名，空的话生成random_str
        :return: 返回传入的文件名（key）以及文件的hash值
        """
        self.filepath = filepath
        targetKey = targetKey if targetKey else "".join((QiNiuService.random_str(), self._fileExtensions))
        token = self.auth.upload_token(self._bucket_name, targetKey, 3600)
        ret, info = put_file(token, targetKey, self.filepath)
        return ret['key'], etag(self.filepath), self.generate_private_url(targetKey)

    def upload_file_by_steam(self, data, targetKey):
        """
        依据字节流上传七牛云
        :param data: 字节流数据
        :param targetKey: 文件名必须
        :return:文件名（key），文件hash值
        """
        # targetKey = targetKey.encode('utf-8')
        token = self.auth.upload_token(self._bucket_name, targetKey, 3600)
        ret, info = put_data(token, targetKey, data)
        return ret['key'], self.generate_private_url(targetKey)

    def download_file(self, key, destinationPath=defaultPath):
        """
        下载七牛云文件到本地
        :param key: 文件名（key）
        :param destinationPath:本地文件，如无则返回默认（根目录下 static\img\origin）
        :return:状态码以及存放文件的完整path
        """
        response = requests.get(self.generate_private_url(key))
        if response.status_code == 200:
            return response.status_code, self.save_file(response, key, destinationPath)
        else:
            return response.status_code, response.reason

    def save_file(self, f, key, destinationPath):
        """
        :param f: 字节流
        :param key: 文件名
        :param destinationPath: 目录
        :return:文件完成path
        """
        if not destinationPath:
            phyPaht = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
            phyPaht = phyPaht.replace("\\", "/")
            path = "/static/img/origin/"
            if not os.path.exists(phyPaht + path):
                os.makedirs(phyPaht + path)
            file_name = phyPaht + path + key
        else:
            file_name = os.path.join(destinationPath, key)
        destination = open(file_name, 'wb+')
        try:
            destination.write(f.content)
            destination.flush()
            destination.close()
        except Exception as e:
            for chunk in f.content.chunks():
                destination.write(chunk)
            destination.close()
        return file_name



